1   /*
2    * Copyright (C) 2011 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5    * in compliance with the License. You may obtain a copy of the License at
6    *
7    * http://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software distributed under the
10   * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
11   * express or implied. See the License for the specific language governing permissions and
12   * limitations under the License.
13   */
14  
15  package com.google.common.primitives;
16  
17  import static com.google.common.base.Preconditions.checkArgument;
18  import static com.google.common.base.Preconditions.checkNotNull;
19  
20  import com.google.common.annotations.Beta;
21  import com.google.common.annotations.GwtCompatible;
22  
23  import java.util.Arrays;
24  import java.util.Comparator;
25  
26  /**
27   * Static utility methods pertaining to {@code int} primitives that interpret values as
28   * <i>unsigned</i> (that is, any negative value {@code x} is treated as the positive value
29   * {@code 2^32 + x}). The methods for which signedness is not an issue are in {@link Ints}, as well
30   * as signed versions of methods for which signedness is an issue.
31   *
32   * <p>In addition, this class provides several static methods for converting an {@code int} to a
33   * {@code String} and a {@code String} to an {@code int} that treat the {@code int} as an unsigned
34   * number.
35   *
36   * <p>Users of these utilities must be <i>extremely careful</i> not to mix up signed and unsigned
37   * {@code int} values. When possible, it is recommended that the {@link UnsignedInteger} wrapper
38   * class be used, at a small efficiency penalty, to enforce the distinction in the type system.
39   *
40   * <p>See the Guava User Guide article on <a href=
41   * "http://code.google.com/p/guava-libraries/wiki/PrimitivesExplained#Unsigned_support">
42   * unsigned primitive utilities</a>.
43   *
44   * @author Louis Wasserman
45   * @since 11.0
46   */
47  @Beta
48  @GwtCompatible
49  public final class UnsignedInts {
50    static final long INT_MASK = 0xffffffffL;
51  
52    private UnsignedInts() {}
53  
54    static int flip(int value) {
55      return value ^ Integer.MIN_VALUE;
56    }
57  
58    /**
59     * Compares the two specified {@code int} values, treating them as unsigned values between
60     * {@code 0} and {@code 2^32 - 1} inclusive.
61     *
62     * @param a the first unsigned {@code int} to compare
63     * @param b the second unsigned {@code int} to compare
64     * @return a negative value if {@code a} is less than {@code b}; a positive value if {@code a} is
65     *         greater than {@code b}; or zero if they are equal
66     */
67    public static int compare(int a, int b) {
68      return Ints.compare(flip(a), flip(b));
69    }
70  
71    /**
72     * Returns the value of the given {@code int} as a {@code long}, when treated as unsigned.
73     */
74    public static long toLong(int value) {
75      return value & INT_MASK;
76    }
77  
78    /**
79     * Returns the least value present in {@code array}, treating values as unsigned.
80     *
81     * @param array a <i>nonempty</i> array of unsigned {@code int} values
82     * @return the value present in {@code array} that is less than or equal to every other value in
83     *         the array according to {@link #compare}
84     * @throws IllegalArgumentException if {@code array} is empty
85     */
86    public static int min(int... array) {
87      checkArgument(array.length > 0);
88      int min = flip(array[0]);
89      for (int i = 1; i < array.length; i++) {
90        int next = flip(array[i]);
91        if (next < min) {
92          min = next;
93        }
94      }
95      return flip(min);
96    }
97  
98    /**
99     * Returns the greatest value present in {@code array}, treating values as unsigned.
100    *
101    * @param array a <i>nonempty</i> array of unsigned {@code int} values
102    * @return the value present in {@code array} that is greater than or equal to every other value
103    *         in the array according to {@link #compare}
104    * @throws IllegalArgumentException if {@code array} is empty
105    */
106   public static int max(int... array) {
107     checkArgument(array.length > 0);
108     int max = flip(array[0]);
109     for (int i = 1; i < array.length; i++) {
110       int next = flip(array[i]);
111       if (next > max) {
112         max = next;
113       }
114     }
115     return flip(max);
116   }
117 
118   /**
119    * Returns a string containing the supplied unsigned {@code int} values separated by
120    * {@code separator}. For example, {@code join("-", 1, 2, 3)} returns the string {@code "1-2-3"}.
121    *
122    * @param separator the text that should appear between consecutive values in the resulting
123    *        string (but not at the start or end)
124    * @param array an array of unsigned {@code int} values, possibly empty
125    */
126   public static String join(String separator, int... array) {
127     checkNotNull(separator);
128     if (array.length == 0) {
129       return "";
130     }
131 
132     // For pre-sizing a builder, just get the right order of magnitude
133     StringBuilder builder = new StringBuilder(array.length * 5);
134     builder.append(toString(array[0]));
135     for (int i = 1; i < array.length; i++) {
136       builder.append(separator).append(toString(array[i]));
137     }
138     return builder.toString();
139   }
140 
141   /**
142    * Returns a comparator that compares two arrays of unsigned {@code int} values lexicographically.
143    * That is, it compares, using {@link #compare(int, int)}), the first pair of values that follow
144    * any common prefix, or when one array is a prefix of the other, treats the shorter array as the
145    * lesser. For example, {@code [] < [1] < [1, 2] < [2] < [1 << 31]}.
146    *
147    * <p>The returned comparator is inconsistent with {@link Object#equals(Object)} (since arrays
148    * support only identity equality), but it is consistent with {@link Arrays#equals(int[], int[])}.
149    *
150    * @see <a href="http://en.wikipedia.org/wiki/Lexicographical_order"> Lexicographical order
151    *      article at Wikipedia</a>
152    */
153   public static Comparator<int[]> lexicographicalComparator() {
154     return LexicographicalComparator.INSTANCE;
155   }
156 
157   enum LexicographicalComparator implements Comparator<int[]> {
158     INSTANCE;
159 
160     @Override
161     public int compare(int[] left, int[] right) {
162       int minLength = Math.min(left.length, right.length);
163       for (int i = 0; i < minLength; i++) {
164         if (left[i] != right[i]) {
165           return UnsignedInts.compare(left[i], right[i]);
166         }
167       }
168       return left.length - right.length;
169     }
170   }
171 
172   /**
173    * Returns dividend / divisor, where the dividend and divisor are treated as unsigned 32-bit
174    * quantities.
175    *
176    * @param dividend the dividend (numerator)
177    * @param divisor the divisor (denominator)
178    * @throws ArithmeticException if divisor is 0
179    */
180   public static int divide(int dividend, int divisor) {
181     return (int) (toLong(dividend) / toLong(divisor));
182   }
183 
184   /**
185    * Returns dividend % divisor, where the dividend and divisor are treated as unsigned 32-bit
186    * quantities.
187    *
188    * @param dividend the dividend (numerator)
189    * @param divisor the divisor (denominator)
190    * @throws ArithmeticException if divisor is 0
191    */
192   public static int remainder(int dividend, int divisor) {
193     return (int) (toLong(dividend) % toLong(divisor));
194   }
195 
196   /**
197    * Returns the unsigned {@code int} value represented by the given string.
198    *
199    * Accepts a decimal, hexadecimal, or octal number given by specifying the following prefix:
200    *
201    * <ul>
202    * <li>{@code 0x}<i>HexDigits</i>
203    * <li>{@code 0X}<i>HexDigits</i>
204    * <li>{@code #}<i>HexDigits</i>
205    * <li>{@code 0}<i>OctalDigits</i>
206    * </ul>
207    *
208    * @throws NumberFormatException if the string does not contain a valid unsigned {@code int} value
209    * @since 13.0
210    */
211   public static int decode(String stringValue) {
212     ParseRequest request = ParseRequest.fromString(stringValue);
213 
214     try {
215       return parseUnsignedInt(request.rawValue, request.radix);
216     } catch (NumberFormatException e) {
217       NumberFormatException decodeException =
218           new NumberFormatException("Error parsing value: " + stringValue);
219       decodeException.initCause(e);
220       throw decodeException;
221     }
222   }
223 
224   /**
225    * Returns the unsigned {@code int} value represented by the given decimal string.
226    *
227    * @throws NumberFormatException if the string does not contain a valid unsigned {@code int} value
228    * @throws NullPointerException if {@code s} is null 
229    *         (in contrast to {@link Integer#parseInt(String)})
230    */
231   public static int parseUnsignedInt(String s) {
232     return parseUnsignedInt(s, 10);
233   }
234 
235   /**
236    * Returns the unsigned {@code int} value represented by a string with the given radix.
237    *
238    * @param string the string containing the unsigned integer representation to be parsed.
239    * @param radix the radix to use while parsing {@code s}; must be between
240    *        {@link Character#MIN_RADIX} and {@link Character#MAX_RADIX}.
241    * @throws NumberFormatException if the string does not contain a valid unsigned {@code int}, or
242    *         if supplied radix is invalid.
243    * @throws NullPointerException if {@code s} is null 
244    *         (in contrast to {@link Integer#parseInt(String)})
245    */
246   public static int parseUnsignedInt(String string, int radix) {
247     checkNotNull(string);
248     long result = Long.parseLong(string, radix);
249     if ((result & INT_MASK) != result) {
250       throw new NumberFormatException("Input " + string + " in base " + radix
251           + " is not in the range of an unsigned integer");
252     }
253     return (int) result;
254   }
255 
256   /**
257    * Returns a string representation of x, where x is treated as unsigned.
258    */
259   public static String toString(int x) {
260     return toString(x, 10);
261   }
262 
263   /**
264    * Returns a string representation of {@code x} for the given radix, where {@code x} is treated
265    * as unsigned.
266    *
267    * @param x the value to convert to a string.
268    * @param radix the radix to use while working with {@code x}
269    * @throws IllegalArgumentException if {@code radix} is not between {@link Character#MIN_RADIX}
270    *         and {@link Character#MAX_RADIX}.
271    */
272   public static String toString(int x, int radix) {
273     long asLong = x & INT_MASK;
274     return Long.toString(asLong, radix);
275   }
276 }